// Copyright (C) 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <iostream>

#include "xml_parse.h"

#include <libxml/parser.h>
#include <libxml/tree.h>

using std::make_pair;
using std::pair;

namespace googleapps {

static pair<ApiResponse, vector<xmlNodePtr> > ParseAtNode(xmlNodePtr root) {
  ApiResponse parsed_nodes;
  vector<xmlNodePtr> unparsed_nodes;

  for (xmlNodePtr cur_node = root->children;
                  cur_node != NULL;
                  cur_node = cur_node->next) {
    string key = reinterpret_cast<const char *>(cur_node->name);

    if (cur_node->children != NULL) {
      if (cur_node->children->type == XML_TEXT_NODE) {
        string value =
            reinterpret_cast<const char *>(cur_node->children->content);
        parsed_nodes[key] = value;
      } else {
        unparsed_nodes.push_back(cur_node);
      }
    } else {
      parsed_nodes[key] = "";
    }
  }

  return make_pair(parsed_nodes, unparsed_nodes);
}

ApiResponse ParseGenericResponse(const string &xml_response) {
  ApiResponse result;
  xmlDocPtr doc = xmlReadMemory(xml_response.c_str(),
                                xml_response.length(),
                                "",
                                NULL,
                                0);

  // Safe due to short-circuit evaluation.
  if (doc != NULL && doc->children != NULL) {
    result = ParseAtNode(doc->children).first;
  }

  xmlFreeDoc(doc);
  return result;
}

AccountResponse ParseRetrieveAccount(const string &xml_response) {
  AccountResponse result;
  pair<ApiResponse, vector<xmlNodePtr> > parse_result;

  xmlDocPtr doc = xmlReadMemory(xml_response.c_str(),
                                xml_response.length(),
                                "",
                                NULL,
                                0);

  // Safe due to short-circuit evaluation.
  if (doc != NULL && doc->children != NULL) {
    parse_result = ParseAtNode(doc->children);
    result.basic_info = parse_result.first;

    // Parse the RetrievalSection.
    if (parse_result.second.size() == 1) {
      parse_result = ParseAtNode(parse_result.second[0]);
      result.retrieval_section = parse_result.first;

      for (unsigned int i = 0; i < parse_result.second.size(); i++) {
        string cur_section =
            reinterpret_cast<const char *>(parse_result.second[i]->name);

        // Parse the aliases and emailLists sections.
        if (cur_section == "aliases") {
          for (xmlNodePtr cur_node = parse_result.second[i]->children;
                          cur_node != NULL;
                          cur_node = cur_node->next) {
            string cur_alias =
                reinterpret_cast<const char *>(cur_node->children->content);
            result.aliases.push_back(cur_alias);
          }
        } else if (cur_section == "emailLists") {
          for (xmlNodePtr cur_node = parse_result.second[i]->children;
                          cur_node != NULL;
                          cur_node = cur_node->next) {
            string cur_list =
                reinterpret_cast<const char *>(cur_node->children->content);
            result.email_lists.push_back(cur_list);
          }
        }
      }
    }
  }

  xmlFreeDoc(doc);
  return result;
}

AddressListResponse ParseRetrieveAddressList(const string &xml_response) {
  AddressListResponse result;

  pair<ApiResponse, vector<xmlNodePtr> > parse_result;

  xmlDocPtr doc = xmlReadMemory(xml_response.c_str(),
                                xml_response.length(),
                                "",
                                NULL,
                                0);

  // Safe due to short-circuit evaluation.
  if (doc != NULL && doc->children != NULL) {
    parse_result = ParseAtNode(doc->children);
    result.basic_info = parse_result.first;

    // Parse the RetrievalSection.
    if (parse_result.second.size() == 1) {
      parse_result = ParseAtNode(parse_result.second[0]);

      for (xmlNodePtr cur_node = parse_result.second[0]->children;
                      cur_node != NULL;
                      cur_node = cur_node->next) {
        string cur_address =
            reinterpret_cast<const char *>(cur_node->children->content);
        result.email_addresses.push_back(cur_address);
      }
    }
  }

  xmlFreeDoc(doc);
  return result;
}

} // End of googleapps namespace
